﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace ArgusPCLib
{
	public abstract class IntIndexedProperty<T> : IEnumerable<T>
	{
		public abstract int Count { get; }
		public abstract T this[int index] { get; set; }

		IEnumerator<T> IEnumerable<T>.GetEnumerator() { return new Enumerator(this); }
		IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); }

		public void CopyTo(T[] array, int startIndex)
		{
			for (int i = 0; i < this.Count; i++)
				array[i + startIndex] = this[i];
		}

		public T[] ToArray()
		{
			T[] RetVal = new T[this.Count];
			this.CopyTo(RetVal, 0);
			return RetVal;
		}

		class Enumerator : IEnumerator<T>
		{
			IntIndexedProperty<T> parent;
			int index;

			public Enumerator(IntIndexedProperty<T> parent)
			{
				this.parent = parent;
			}

			public void Reset()
			{
				this.index = -1;
			}

			public bool MoveNext()
			{
				this.index++;
				return this.index < this.parent.Count;
			}

			public T Current { get { return this.parent[this.index]; } }
			object IEnumerator.Current { get { return this.Current; } }

			public void Dispose() { this.parent = null; }
		}
	}

	public abstract class IntIndexedPropertyGet<T> : IEnumerable<T>
	{
		public abstract int Count { get; }
		public abstract T this[int index] { get; }

		IEnumerator<T> IEnumerable<T>.GetEnumerator() { return new Enumerator(this); }
		IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); }

		public void CopyTo(T[] array, int startIndex)
		{
			for (int i = 0; i < this.Count; i++)
				array[i + startIndex] = this[i];
		}

		public T[] ToArray()
		{
			T[] RetVal = new T[this.Count];
			this.CopyTo(RetVal, 0);
			return RetVal;
		}

		class Enumerator : IEnumerator<T>
		{
			IntIndexedPropertyGet<T> parent;
			int index;

			public Enumerator(IntIndexedPropertyGet<T> parent)
			{
				this.parent = parent;
			}

			public void Reset()
			{
				this.index = -1;
			}

			public bool MoveNext()
			{
				this.index++;
				return this.index < this.parent.Count;
			}

			public T Current { get { return this.parent[this.index]; } }
			object IEnumerator.Current { get { return this.Current; } }

			public void Dispose() { this.parent = null; }
		}
	}

	public class IndexedProperty<TProperty, TIndex>
	{
		public delegate TProperty GetHandler(TIndex index);
		public delegate void SetHandler(TIndex index, TProperty value);

		GetHandler getHandler;
		SetHandler setHandler;

		public IndexedProperty(GetHandler getHandler, SetHandler setHandler)
		{
			this.getHandler = getHandler;
			this.setHandler = setHandler;
		}

		public TProperty this[TIndex index]
		{
			get { return this.getHandler(index); }
			set { this.setHandler(index, value); }
		}
	}

	public class IndexedProperty<TProperty, TIndex1, TIndex2>
	{
		public delegate TProperty GetHandler(TIndex1 index1, TIndex2 index2);
		public delegate void SetHandler(TIndex1 index1, TIndex2 index2, TProperty value);

		GetHandler getHandler;
		SetHandler setHandler;

		public IndexedProperty(GetHandler getHandler, SetHandler setHandler)
		{
			this.getHandler = getHandler;
			this.setHandler = setHandler;
		}

		public TProperty this[TIndex1 index1, TIndex2 index2]
		{
			get { return this.getHandler(index1, index2); }
			set { this.setHandler(index1, index2, value); }
		}
	}

	public class IndexedProperty<TProperty, TIndex1, TIndex2, TIndex3>
	{
		public delegate TProperty GetHandler(TIndex1 index1, TIndex2 index2, TIndex3 index3);
		public delegate void SetHandler(TIndex1 index1, TIndex2 index2, TIndex3 index3, TProperty value);

		GetHandler getHandler;
		SetHandler setHandler;

		public IndexedProperty(GetHandler getHandler, SetHandler setHandler)
		{
			this.getHandler = getHandler;
			this.setHandler = setHandler;
		}

		public TProperty this[TIndex1 index1, TIndex2 index2, TIndex3 index3]
		{
			get { return this.getHandler(index1, index2, index3); }
			set { this.setHandler(index1, index2, index3, value); }
		}
	}

	public class IndexedPropertyGet<TProperty, TIndex>
	{
		public delegate TProperty GetHandler(TIndex index);

		GetHandler getHandler;

		public IndexedPropertyGet(GetHandler getHandler)
		{
			this.getHandler = getHandler;
		}

		public TProperty this[TIndex index]
		{
			get { return this.getHandler(index); }
		}
	}

	public class IndexedPropertyGet<TProperty, TIndex1, TIndex2>
	{
		public delegate TProperty GetHandler(TIndex1 index1, TIndex2 index2);

		GetHandler getHandler;

		public IndexedPropertyGet(GetHandler getHandler)
		{
			this.getHandler = getHandler;
		}

		public TProperty this[TIndex1 index1, TIndex2 index2]
		{
			get { return this.getHandler(index1, index2); }
		}
	}

	public class IndexedPropertyGet<TProperty, TIndex1, TIndex2, TIndex3>
	{
		public delegate TProperty GetHandler(TIndex1 index1, TIndex2 index2, TIndex3 index3);

		GetHandler getHandler;

		public IndexedPropertyGet(GetHandler getHandler)
		{
			this.getHandler = getHandler;
		}

		public TProperty this[TIndex1 index1, TIndex2 index2, TIndex3 index3]
		{
			get { return this.getHandler(index1, index2, index3); }
		}
	}
}
